package bridge

import (
	"encoding/json"
	"fmt"
	"reflect"
	"strings"

	"gitee.com/tomatomeatman/golang-repository/bricks3/function/configutil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/httputil"
	"gitee.com/tomatomeatman/golang-repository/bricks3/function/urlutil"
	Log "github.com/cihub/seelog"
	"github.com/gin-gonic/gin"
)

/**
 * 桥接数据操作结构体
 */
type BridgeDao struct {
}

var (
	cloudCenterUrl = "" //Cloud注册中心地址(分布式时使用)
	// cloudCenterUser = "" //Cloud注册中心用户名称(分布式时使用)
	cloudCenterPass = "" //Cloud注册中心用户密码(分布式时使用)
	domainName      = "" //项目所在域名
)

// 初始化
func init() {
	if configutil.HasSection("./config/app.ini", "CloudCenter") { //禁用桥接
		return
	}

	cloudCenterUrl = configutil.ReadConfigKey("", "CloudCenter", "Site", "").(string)
	// cloudCenterUser = configutil.ReadConfigKey("", "CloudCenter", "User", "").(string)
	cloudCenterPass = configutil.ReadConfigKey("", "CloudCenter", "Password", "").(string)
	domainName = configutil.ReadConfigKey("", "CloudCenter", "DomainName", "").(string)
}

/**
 * post请求
 * @param serverName 服务名
 * @param url 请求的相对路径
 * @param parameters 请求参数
 * @param resultType 返回类型
 * @param isResultList 返沪类型是否list
 * @return
 */
func (dao BridgeDao) Post(ctx *gin.Context, serverName, url string, parameters map[string]interface{}, resultType interface{}) (bool, string, interface{}) {
	hearMap := urlutil.GetHeader(ctx.Request) //取请求头参数
	return dao.post(serverName, url, parameters, resultType, hearMap)
}

/**
 * 代理请求post
 * 注意:要求请求方返回的必须是*msgentity.MsgEntity类型
 * @return
 */
func (dao BridgeDao) ProxyPost(ctx *gin.Context) (bool, string, interface{}) {
	domainName := urlutil.GetParam(ctx.Request, "domainName", "GBaseSystemServer").(string)
	url := string([]rune(ctx.Request.URL.String())[6:])

	params := urlutil.GetParamsAll(ctx.Request, false)
	hearMap := urlutil.GetHeader(ctx.Request) //取请求头参数

	var result map[string]interface{}
	bl, msg, res := dao.post(domainName, url, params, &result, hearMap)
	if !bl {
		return bl, msg, res
	}

	return result["success"].(bool), result["msg"].(string), result["data"]
}

/**
 * 代理请求get
 * 注意:要求请求方返回的必须是*msgentity.MsgEntity类型
 * @return
 */
func (dao BridgeDao) ProxyGet(ctx *gin.Context) (bool, string, interface{}) {
	domainName := urlutil.GetParam(ctx.Request, "domainName", "GBaseSystemServer").(string)
	url := string([]rune(ctx.Request.URL.String())[6:])

	params := urlutil.GetParamsAll(ctx.Request, false)
	hearMap := urlutil.GetHeader(ctx.Request) //取请求头参数

	var result map[string]interface{}
	bl, msg, res := dao.get(domainName, url, params, &result, hearMap)
	if !bl {
		return bl, msg, res
	}

	return result["success"].(bool), result["msg"].(string), result["data"]
}

/**
 * GET请求
 * @param serverName 服务名
 * @param url 请求的相对路径
 * @param resultType 返回类型
 * @param isResultList 返沪类型是否list
 * @return
 */
func (dao BridgeDao) Get(ctx *gin.Context, serverName, url string, parameters map[string]interface{}, resultType interface{}) (bool, string, interface{}) {
	hearMap := urlutil.GetHeader(ctx.Request) //取请求头参数
	return dao.get(serverName, url, parameters, resultType, hearMap)
}

/**
 * post请求
 * @param serverName 服务名
 * @param url 请求的相对路径
 * @param parameters 请求参数
 * @param resultType 返回类型
 * @param hearMap 自定义请求头
 * @return
 */
func (dao BridgeDao) post(serverName, url string, parameters map[string]interface{},
	resultType interface{}, hearMap map[string]string) (bool, string, interface{}) {
	bl, msg, res := dao.findServerSite(serverName)
	if !bl {
		return bl, msg, res
	}

	params := map[string]interface{}{}
	if len(parameters) > 0 {
		for key, val := range parameters {
			params[key] = val
		}
	}

	url = res.(string) + url
	bl, msg, res = httputil.DoPost(url, params, hearMap)
	if !bl {
		return bl, msg, res
	}

	if res == nil {
		return false, "调用POST未能获取指定结果", 8001
	}

	if resultType == nil {
		return bl, msg, res
	}

	if reflect.TypeOf(resultType).String() == "string" {
		return bl, msg, res
	}

	str := string(res.([]uint8))
	err := json.Unmarshal([]byte(str), resultType)
	if err != nil {
		Log.Error("Json字符串转换异常: ", err)
		return false, "内容转换发生异常", 8003
	}

	return bl, msg, resultType
}

/**
 * GET请求
 * @param serverName 服务名
 * @param url 请求的相对路径
 * @param resultType 返回类型
 * @param hearMap 自定义请求头
 * @return
 */
func (dao BridgeDao) get(serverName, url string, parameters map[string]interface{},
	resultType interface{}, hearMap map[string]string) (bool, string, interface{}) {
	bl, msg, res := dao.findServerSite(serverName)
	if !bl {
		return bl, msg, res
	}

	//url = strings.ReplaceAll(res.(string)+url, "//", "/")
	url = res.(string) + url
	bl, msg, data := httputil.DoGet(url, parameters, hearMap)
	if !bl {
		return bl, msg, data
	}

	if res == nil {
		return false, "调用POST未能获取指定结果", 8001
	}

	if resultType == nil {
		return bl, msg, res
	}

	if reflect.TypeOf(resultType).String() == "string" {
		return bl, msg, res
	}

	err := json.Unmarshal([]byte(res.(string)), &resultType)
	if err != nil {
		Log.Error("Json字符串转换异常: %+v\n", err)
		return false, "内容转换发生异常", 8002
	}

	return bl, msg, resultType
}

/**
 * 访问注册中心,获取服务地址
 * @param serverName
 * @param cloudCenterUrl
 * @return
 */
func (dao BridgeDao) findServerSite(serverName string) (bool, string, interface{}) {
	if cloudCenterUrl == "" {
		return false, "项目未配置注册中心地址,配置项'cloud.center.site'", 7101
	}

	url := strings.ReplaceAll(fmt.Sprintf("http://%s/find/name?Name=%s&key=%s", cloudCenterUrl, serverName, cloudCenterPass), "http://http://", "http://")
	bl, msg, data := httputil.DoGet(url, nil, nil)
	if !bl {
		return bl, msg, data
	}

	var result map[string]interface{}
	err := json.Unmarshal([]byte(data.(string)), &result)
	if err != nil {
		return false, "访问注册中心失败,未能获取预期信息", 7102
	}

	if result["data"] == nil {
		return false, "访问注册中心失败,未能获取预期信息", 7102
	}

	if !result["success"].(bool) {
		if reflect.TypeOf(result["data"]).String() == "int" {
			result["data"] = result["data"].(int) + 200
			return result["success"].(bool), result["msg"].(string), result["data"]
		}

		return result["success"].(bool), result["msg"].(string), result["data"]
	}

	m := result["data"].(map[string]interface{})

	if (m["domainName"] == nil) || (m["domainName"] == "") { //没有启用域名
		result["data"] = fmt.Sprintf("http://%s:%s", m["serverIp"], m["serverPort"])
		return result["success"].(bool), result["msg"].(string), result["data"]
	}

	if (m["domainName"] != "") && (domainName == m["domainName"]) { //启用域名,但域名与本程序一致,则属于同一个服务器或同一个局域网内
		result["data"] = fmt.Sprintf("http://%s:%s", m["serverIp"], m["serverPort"]) //通过ip和端口访问
		return result["success"].(bool), result["msg"].(string), result["data"]
	}

	if (m["domainPort"] == nil) || (m["domainPort"] == "") { //启用域名但没有使用端口,则端口为80
		result["data"] = fmt.Sprintf("http://%s", m["domainName"])
		return result["success"].(bool), result["msg"].(string), result["data"]
	}

	//启用域名且使用指定端口

	return result["success"].(bool), result["msg"].(string), fmt.Sprintf("http://%s:%s", m["domainName"], m["domainPort"])
}
